package com.lcifn.middleware.rpc;

import com.lcifn.middleware.rpc.client.StubFactory;
import com.lcifn.middleware.rpc.server.ServiceProviderRegistry;
import com.lcifn.middleware.rpc.spi.ServiceSupport;
import com.lcifn.middleware.rpc.transport.Transport;
import com.lcifn.middleware.rpc.transport.TransportClient;
import com.lcifn.middleware.rpc.transport.TransportServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;

/**
 * rpc服务接口的netty实现
 * @author lichao
 * @date 2020/12/13 17:28
 */
public class NettyRpcAccessPoint implements RpcAccessPoint {
    private static final Logger logger = LoggerFactory.getLogger(NettyRpcAccessPoint.class);

    private final String host = "127.0.0.1";
    private final int port = 9999;
    private final URI serviceUri = URI.create("rpc://" + host + ":" + port);

    // 连接超时时间
    private final int connectTimeout = 30000;

    // 传输客户端实现
    private TransportClient client = ServiceSupport.load(TransportClient.class);
    // 传输服务端
    private TransportServer server;
    // 传输客户端Map
    private Map<URI, Transport> clientMap = new ConcurrentHashMap<>();
    // 桩工厂实现
    private StubFactory stubFactory = ServiceSupport.load(StubFactory.class);
    // 服务提供者注册器
    private ServiceProviderRegistry registry = ServiceProviderRegistry.getInstance();

    /**
     * 客户端获取远程服务的引用
     * @param uri
     * @param serviceClass
     * @return T
     * @author lichao 2021/1/31 14:14
     */
    @Override
    public <T> T getRemoteService(URI uri, Class<T> serviceClass) {
        Transport transport = clientMap.computeIfAbsent(uri, this::createTransport);
        return stubFactory.createStub(transport, serviceClass);
    }

    /**
     * 创建Transport
     * @param uri
     * @return com.lcifn.middleware.rpc.transport.Transport
     * @author lichao 2021/1/31 14:14
     */
    private Transport createTransport(URI uri) {
        try {
            return client.createTransport(new InetSocketAddress(uri.getHost(), uri.getPort()), connectTimeout);
        } catch (InterruptedException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> URI addServiceProvider(Class<T> serviceClass, T service) {
        registry.addService(serviceClass, service);
        return serviceUri;
    }

    /**
     * RPC服务启动
     *
     * @return
     */
    @Override
    public Closeable startServer() throws Exception {
        if (server == null) {
            server = ServiceSupport.load(TransportServer.class);
            server.start(port);
        }

        return () -> {
            if (null != server) {
                server.stop();
            }
        };
    }
}
